//! 收益率特征计算模块
//! 
//! 提供各种收益率相关的技术指标计算

use crate::objects::RawBar;
use serde::{Deserialize, Serialize};
use chrono::{DateTime, Utc};

/// 收益率特征配置
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct RetConfig {
    /// 计算周期
    pub period: String,
    /// 年化基准
    pub annual_basis: f64,
}

/// 收益率特征计算器
#[derive(Debug, Clone)]
pub struct RetFeatures {
    config: RetConfig,
}

impl RetFeatures {
    /// 创建新的收益率特征计算器
    pub fn new(config: RetConfig) -> Self {
        Self { config }
    }

    /// 计算简单收益率
    pub fn simple_return(&self, current_price: f64, previous_price: f64) -> f64 {
        if previous_price == 0.0 {
            return 0.0;
        }
        (current_price - previous_price) / previous_price
    }

    /// 计算对数收益率
    pub fn log_return(&self, current_price: f64, previous_price: f64) -> f64 {
        if previous_price <= 0.0 || current_price <= 0.0 {
            return 0.0;
        }
        (current_price / previous_price).ln()
    }

    /// 计算累计收益率
    pub fn cumulative_return(&self, prices: &[f64]) -> Vec<f64> {
        if prices.is_empty() {
            return vec![];
        }
        
        let mut cumulative_returns = Vec::new();
        let initial_price = prices[0];
        
        for &price in prices {
            let return_rate = self.simple_return(price, initial_price);
            cumulative_returns.push(return_rate);
        }
        
        cumulative_returns
    }

    /// 计算年化收益率
    pub fn annualized_return(&self, total_return: f64, years: f64) -> f64 {
        if years <= 0.0 {
            return 0.0;
        }
        (1.0 + total_return).powf(1.0 / years) - 1.0
    }

    /// 计算最大回撤
    pub fn max_drawdown(&self, prices: &[f64]) -> f64 {
        if prices.is_empty() {
            return 0.0;
        }
        
        let mut max_price = prices[0];
        let mut max_drawdown = 0.0;
        
        for &price in prices {
            if price > max_price {
                max_price = price;
            }
            let drawdown = (max_price - price) / max_price;
            if drawdown > max_drawdown {
                max_drawdown = drawdown;
            }
        }
        
        max_drawdown
    }

    /// 计算夏普比率
    pub fn sharpe_ratio(&self, returns: &[f64], risk_free_rate: f64) -> f64 {
        if returns.is_empty() {
            return 0.0;
        }
        
        let mean_return: f64 = returns.iter().sum::<f64>() / returns.len() as f64;
        let variance: f64 = returns.iter()
            .map(|r| (r - mean_return).powi(2))
            .sum::<f64>() / returns.len() as f64;
        let std_dev = variance.sqrt();
        
        if std_dev == 0.0 {
            return 0.0;
        }
        
        (mean_return - risk_free_rate) / std_dev
    }

    /// 计算波动率
    pub fn volatility(&self, returns: &[f64]) -> f64 {
        if returns.is_empty() {
            return 0.0;
        }
        
        let mean_return: f64 = returns.iter().sum::<f64>() / returns.len() as f64;
        let variance: f64 = returns.iter()
            .map(|r| (r - mean_return).powi(2))
            .sum::<f64>() / returns.len() as f64;
        
        variance.sqrt()
    }

    /// 计算VaR (Value at Risk)
    pub fn var(&self, returns: &[f64], confidence_level: f64) -> f64 {
        if returns.is_empty() {
            return 0.0;
        }
        
        let mut sorted_returns = returns.to_vec();
        sorted_returns.sort_by(|a, b| a.partial_cmp(b).unwrap());
        
        let index = ((1.0 - confidence_level) * returns.len() as f64) as usize;
        if index < sorted_returns.len() {
            sorted_returns[index]
        } else {
            0.0
        }
    }

    /// 计算所有收益率特征
    pub fn calculate_all_features(&self, prices: &[f64]) -> serde_json::Value {
        if prices.len() < 2 {
            return serde_json::json!({
                "error": "价格数据不足，无法计算特征"
            });
        }
        
        // 计算收益率序列
        let mut returns = Vec::new();
        for i in 1..prices.len() {
            returns.push(self.simple_return(prices[i], prices[i-1]));
        }
        
        // 计算各种特征
        let total_return = self.simple_return(prices[prices.len()-1], prices[0]);
        let cumulative_returns = self.cumulative_return(prices);
        let max_dd = self.max_drawdown(prices);
        let volatility = self.volatility(&returns);
        let sharpe = self.sharpe_ratio(&returns, 0.02); // 假设无风险利率为2%
        let var_95 = self.var(&returns, 0.95);
        
        serde_json::json!({
            "total_return": total_return,
            "annualized_return": self.annualized_return(total_return, 1.0), // 假设1年
            "max_drawdown": max_dd,
            "volatility": volatility,
            "sharpe_ratio": sharpe,
            "var_95": var_95,
            "return_count": returns.len(),
            "price_count": prices.len(),
            "mean_return": returns.iter().sum::<f64>() / returns.len() as f64,
            "min_return": returns.iter().fold(f64::INFINITY, |a, &b| a.min(b)),
            "max_return": returns.iter().fold(f64::NEG_INFINITY, |a, &b| a.max(b))
        })
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_simple_return() {
        let config = RetConfig {
            period: "daily".to_string(),
            annual_basis: 252.0,
        };
        let ret_features = RetFeatures::new(config);
        
        assert_eq!(ret_features.simple_return(110.0, 100.0), 0.1);
        assert_eq!(ret_features.simple_return(90.0, 100.0), -0.1);
    }

    #[test]
    fn test_log_return() {
        let config = RetConfig {
            period: "daily".to_string(),
            annual_basis: 252.0,
        };
        let ret_features = RetFeatures::new(config);
        
        let log_ret = ret_features.log_return(110.0, 100.0);
        assert!((log_ret - 0.09531017980432493).abs() < 1e-10);
    }

    #[test]
    fn test_max_drawdown() {
        let config = RetConfig {
            period: "daily".to_string(),
            annual_basis: 252.0,
        };
        let ret_features = RetFeatures::new(config);
        
        let prices = vec![100.0, 110.0, 105.0, 120.0, 115.0, 130.0];
        let max_dd = ret_features.max_drawdown(&prices);
        assert!((max_dd - 0.125).abs() < 1e-10); // (120-105)/120 = 0.125
    }
} 